#!/usr/bin/python
#coding:utf-8
'''
孤立森林算法
思想：假设我们用一个随机超平面来切割（split）数据空间（data space）, 切一次可以生成两个子空间（想象拿刀切蛋糕一分为二）。之后我们再继续用一个随机超平面来切割每个子空间，循环下去，直到每子空间里面只有一个数据点为止。直观上来讲，我们可以发现那些密度很高的簇是可以被切很多次才会停止切割，但是那些密度很低的点很容易很早的就停到一个子空间了。
    特点：
        1、不适用高纬数据
        2、适用连续数据的异常检测
'''
import numpy as np 
import matplotlib.pyplot as plt
from sklearn.ensemble import IsolationForest

from pylab import mpl


def method():
    mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
    mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题


    rng = np.random.RandomState(42)

    #Generate train data
    x=0.3 * rng.randn(100,2)
    x_train = np.r_[x+1,x-3,x-5,x+6]

    x= 0.3* rng.randn(20,2)
    x_test= np.r_[x+1,x-3,x-5,x+6]

    x_outliers=rng.uniform(low=-8,high=8,size=(20,2))

    clf=IsolationForest(max_samples=100*2,random_state=rng)
    clf.fit(x_train)
    y_pred_train = clf.predict(x_train)
    y_pred_outliers= clf.predict(x_outliers)

    print(y_pred_train.shape)
    print(y_pred_train)

    print(x_test.shape)  #80,2
    print(x_train.shape) #400,2 
    print(x_outliers.shape) #20,2
    return x_test,x_train,x_outliers,plt

def show(x_test,x_train,x_outliers,plt):
    #绘制图像
    xx,yy=np.meshgrid(np.linspace(-8,8,50),np.linspace(-8,8,50))
    z=clf.decision_function(np.c_[xx.ravel(),yy.ravel()])
    z=z.reshape(xx.shape)

    plt.title("IsolationForest")
    plt.contourf(xx,yy,z,cmap=plt.cm.Blues_r)

    b1= plt.scatter(x_train[:,0],x_train[:,1],c='white')
    b2=plt.scatter(x_test[:,0],x_test[:,1],c='green')
    c=plt.scatter(x_outliers[:,0],x_outliers[:,1],c='red')
    plt.axis('tight')
    plt.xlim((-8,8))
    plt.ylim((-8,8))
    plt.legend([b1,b2,c],
                ["训练集",  #训练集
                "测试集合","异常点"], #测试集 异常点
                loc="upper left")
    plt.show()

method()